#![deny(missing_docs, missing_debug_implementations, unused_imports, dead_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
// Disallow warnings when running tests.
#![cfg_attr(test, deny(warnings))]
//! Coolink SDK run on openharmony.
//! Usage:
//! ## SDKContract::init_sdk("coolink".toString(),"DEBUG".toString())
use serde::{Deserialize, Serialize};

/// SDKApiResult is result wrap for api interface caller.
#[derive(thiserror::Error, Debug, Serialize, Deserialize)]
pub struct SDKApiResult {
    /// code: return code for sdk api function,if < 0 then failed,if >= 0,then continue.
    #[serde(rename = "code")]
    pub code: i64,
    /// msg: if code >=0 ,msg is Ok or continue message, if code < 0,msg is error message.
    #[serde(rename = "msg")]
    pub msg: String,
}

/// SGWebSocketCallBack is a signal gateway callback implemenataion by websocket protocol,
/// CoolLink ohos sdk use this trait to exchange the signals.
pub trait SGWebSocketCallBack: Sync + Send {
    /// received message from signal gateway
    fn on_sg_message(
        &self,
        data: String, // message data
    ) -> i64;
    /// received be online from signal gateway
    fn on_sg_online(
        &self,
        client_id: String,          // unique client id
        turn_host: String,          // ice turn host address for NAT punching
        turn_user_name: String,     // ice turn user
        turn_user_password: String, // ice turn password
    ) -> i64;
    /// received ping heart beat from signal gateway
    fn on_sg_ping(&self);
    /// signal gateway occus error!
    fn on_sg_error(&self, err_msg: String) -> i64;
    /// received reconnect request message from signal gateway
    fn on_sg_need_reconnect(
        &self,
        err_msg: String, // the reason for need reconnect
    ) -> i64;
    /// received message replay from signal gateway, send_message_id is returned by send_signal_to() function.
    fn on_sg_send_reply(
        &self,
        send_message_id: String, // the message id last time send.
        is_ok: bool,             // is send ok
        reason: String,          // if is_ok is false ,the reason replay.
    ) -> i64;
}

/// SGWebSocketContract is a signal gateway implemenataion by websocket protocol,
/// CoolLink ohos sdk use this trait to exchange the signals.
pub trait SGWebSocketContract {
    /// init_sg_sdk :set application tag and log level.
    fn init_sg_sdk(tag: String, log_level: String) -> SDKApiResult;

    /// loop_block_on_connect_sg: connect to signal gateway, loop block means infinity run or unwrap inner then break.
    fn loop_block_on_connect_sg(
        sg_host: String,                           // gateway url host address
        sg_subgroup_path: String,                  // gateway url subgroup path
        sg_access_key: String,                     // gateway registed http request auth access key
        sg_access_secret: String, // gateway registed http request auth access secret,corresponding for access key
        local_app_package: String, // gateway registed app package name
        local_device_id: String,  // regist to gateway local unique device id
        local_user_id: String,    // regist to gateway local unique user id
        sg_callback: Box<dyn SGWebSocketCallBack>, // function call back
        config_file_saved_path: String, //config file saved path.
    ) -> SDKApiResult;

    /// block_query_sg_client_id: query clent id from signal gateway not in thread.
    fn block_query_sg_client_id(
        sg_host: String,          // gateway query clientid url host address
        sg_subgroup_path: String, //  gateway query clientid url subgroup path
        sg_access_key: String,    // gateway registed http request auth access key
        sg_access_secret: String, // gateway registed http request auth access secret,corresponding for access key
        app_package: String,      // gateway registed app package name
        device_id: String,        // regist to gateway local unique device id
        user_id: String,          // regist to gateway local unique user id
    ) -> SDKApiResult;

    /// block_query_sg_is_online: query clent is on line from signal gateway not in thread.
    fn block_query_sg_is_online(
        sg_host: String,          // gateway query client is online url host address
        sg_subgroup_path: String, //  gateway query client is online url subgroup path
        sg_access_key: String,    // gateway registed http request auth access key
        sg_access_secret: String, // gateway registed http request auth access secret,corresponding for access key
        sg_client_id: String,     // regist to gateway unique client id
    ) -> SDKApiResult;

    /// send_message_sg_relay_to: local device send message to target unique_client_id,relay by gateway
    fn send_message_sg_relay_to(
        unique_client_id: String, // target unique_client_id
        event_name: String,       // message event name
        event_data: String,       // message event data
        qos: i32,                 // message qos level,default = 0
    ) -> SDKApiResult;

    /// had_connected_sg: check if local device was connected to the gateway.
    fn had_connected_sg() -> i32; // if <=0 means disconnected

    /// disconnect_sg: disconnected from the signal gateway.
    fn disconnect_sg() -> SDKApiResult;
}

/// P2PRPCServiceCallback is a p2p rpc server callback implemenataion
pub trait P2PRPCServiceCallback: Sync + Send {
    /// received p2prcp server created event
    fn on_p2prpc_server_created(
        &self,
        local_client_id: String, //always equal to on_sg_online return local_client_id
    ) -> i64;
    /// received p2prcp server droped event
    fn on_p2prpc_server_droped(
        &self,
        reason: String, // p2prpc server dropped with some reason
    ) -> i64;
    /// received p2prpc data transport tunnel created, a p2prpc server can handle many tunnels.
    fn on_p2prpc_tunnel_created(
        &self,
        tunnel_id: String,        //  p2prpc tunnel of unique tunnel id
        local_client_id: String,  // local_client_id for p2prpc tunnel
        remote_client_id: String, // remote_client_id for p2prpc tunnel
        is_controlling: bool,     // check if local_client_id is controlling role.
    ) -> i64;
    /// received p2prpc pair tunnel destroyed
    fn on_p2prpc_tunnel_destroy(
        &self,
        tunnel_id: String,        //  p2prpc tunnel of unique tunnel id
        local_client_id: String,  // local_client_id for p2prpc tunnel
        remote_client_id: String, // remote_client_id for p2prpc tunnel
    ) -> i64;
    /// received ice-kcp tunnel state changged
    fn on_p2prpc_tunnel_state_changed(
        &self,
        tunnel_id: String,        //  p2prpc tunnel of unique tunnel id
        local_client_id: String,  // local_client_id for p2prpc tunnel
        remote_client_id: String, // remote_client_id for p2prpc tunnel
        state: String,            // p2prpc tunnel current state
        state_msg: String,
    ) -> i64;
    /// received ice-kcp tunnel pair changged
    fn on_p2prpc_tunnel_pair_changed(
        &self,
        tunnel_id: String,        //  p2prpc tunnel of unique tunnel id
        local_client_id: String,  // local_client_id for p2prpc tunnel
        remote_client_id: String, // remote_client_id for p2prpc tunnel
        mine_pair: String,        // my tunnel ip/port pair
        remote_pair: String,      // remote tunnel ip/port pair
    ) -> i64;

    /// received text tunnel selected as duplex rpc tunnel
    fn on_text_tunnel_select_duplex(
        &self,
        tunnel_id: String,        // p2prpc tunnel of unique tunnel id
        local_client_id: String,  //  local_client_id for p2prpc tunnel
        remote_device_id: String, // remote_client_id for p2prpc tunnel
    ) -> i64;

    /// received text tunnel canceled as duplex rpc tunnel
    fn on_text_tunnel_cancel_duplex(
        &self,
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> i64;

    /// received text message from tunnel
    fn on_p2prpc_tunnel_rec_msg(
        &self,
        tunnel_id: String,        // p2prpc tunnel of unique tunnel id
        local_client_id: String,  //  local_client_id of this p2prpc pair tunnel
        remote_client_id: String, // remote_device_id of this p2prpc pair tunnel
        msg_id: String,           // unique msgid received
        event: String,            // message event received
        data: String,             // message data received
    ) -> i64;

    /// received byte buffer message from tunnel
    fn on_p2prpc_tunnel_rec_bytebuffer(
        &self,
        tunnel_id: String,  // p2prpc tunnel of unique tunnel id
        buffer_id: String,  // unique bytebuffer id received
        video_buf: Vec<u8>, // video bytebuffer received
        audio_buf: Vec<u8>, // audio bytebuffer received
    ) -> i64;

    /// send message with text tunnel replay result
    fn on_p2prpc_send_msg_result(
        &self,
        msg_id: String,    // unique msgid sent
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
        is_ok: bool,       // message sent is ok
        err_msg: String,   // if is_ok == false,error message print
    ) -> i64;

    /// send bytebuffer with bytebuffer tunnel replay result
    fn on_p2prpc_send_bytebuffer_result(
        &self,
        buffer_id: String, // unique bytebuffer sent
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
        is_ok: bool,       // bytebuffer sent is ok
        err_msg: String,   // if is_ok == false,error message print
    ) -> i64;

    /// received bytebuffer tunnel selected as duplex rpc tunnel
    fn on_bybebuf_tunnel_select_duplex(
        &self,
        tunnel_id: String,        // p2prpc tunnel of unique tunnel id
        local_client_id: String,  //  local_client_id of this p2prpc pair tunnel
        remote_device_id: String, //  remote_device_id of this p2prpc pair tunnel
    ) -> i64;

    /// received bytebuffer tunnel canceled as duplex rpc tunnel
    fn on_bybebuf_tunnel_cancel_duplex(
        &self,
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> i64;
}

/// P2PRPCServiceContract is the P2PRPC server implemenatation.
pub trait P2PRPCServiceContract {
    /// init_sg_sdk :set application tag and log level.
    fn init_p2prpc_sdk(tag: String, log_level: String) -> SDKApiResult;

    /// loop_block_on_start_p2prpc_server: loop start p2prtc server, loop block means infinity run or unwrap inner then break.
    fn loop_block_on_start_p2prpc_server(
        sg_host: String,          // gateway query clientid url host address
        sg_subgroup_path: String, //  gateway query clientid url subgroup path
        sg_access_key: String,    // gateway registed http request auth access key
        sg_access_secret: String, // gateway registed http request auth access secret,corresponding for access key

        config_file_saved_path: String,    // config file saved path
        download_files_saved_path: String, // download files saved path
        enable_httpd_callback: bool,       // is enable http deamon callback
        p2prpc_callback: Box<dyn P2PRPCServiceCallback>, //p2prpc call back dyn point
        ice_turn_config_json: String,      // ice turn config json string, mapping to TurnAddrs
    ) -> SDKApiResult;

    /// stop p2prpc server
    fn stop_p2prpc_server() -> SDKApiResult;

    /// block_on_make_p2prpc_tunnel:  loop make p2prtc tunnel, loop block means infinity run or unwrap inner then break.
    fn block_on_make_p2prpc_tunnel(
        local_client_id: String,  //local_client_id of this p2prpc pair tunnel
        remote_client_id: String, // remote_device_id of this p2prpc pair tunnel
        tunnel_id: String,        // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;

    /// drop the p2prpc tunnel
    fn drop_p2prpc_tunnel(tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;

    /// select the p2prpc tunnel as duplex text tunnel
    fn select_text_tunnel_duplex(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;
    /// cancel the p2prpc tunnel as duplex text tunnel
    fn cancel_text_tunnel_duplex(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;

    /// select the p2prpc tunnel as duplex bytebuffer tunnel
    fn select_bytebuf_tunnel_duplex(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;
    /// cancel the p2prpc tunnel as duplex bytebuffer tunnel
    fn cancel_bytebuf_tunnel_duplex(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
    ) -> SDKApiResult;

    /// send message with p2prpc text tunnel
    fn send_text_message(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
        id: String,        // the unique message id
        event: String,     // message event name
        data: String,      // message data
        can_drop: bool,    // can drop means this message can drop when network traffic busy
    ) -> SDKApiResult;

    /// send bytebuffer with p2prpc bytebuffer channel
    fn send_bytebuffer(
        tunnel_id: String,  // p2prpc tunnel of unique tunnel id
        id: String,         // the unique message id
        video_buf: Vec<u8>, // the video buffer vec
        audio_buf: Vec<u8>, // the audio buffer vec
        can_drop: bool,     //  can drop means this bytebuffer can drop when network traffic busy
    ) -> SDKApiResult;

    /// network_change_refresh_candidate:notify rpc tunnel device network drop or online
    fn network_change_refresh_candidate(
        is_online: bool, //notify network is online or offline
    ) -> SDKApiResult;

    /// notify_netwosoft_link_file_mapping:
    fn soft_link_file_mapping(
        add_or_remove: u8, // add or remove local file soft link to rpc mapping. 1 = add,0 = remove
        file_path: String, // local file abstract path.
    ) -> SDKApiResult;

    /// is_p2prpc_remote_in_lan: check if the p2pprc tunnel pair is on the same lan.
    fn is_p2prpc_remote_in_lan(
        tunnel_id: String, // p2prpc tunnel of unique tunnel id
        remote_id: String, // p2prpc pair of remote id.
    ) -> SDKApiResult;
}

/// HttpdImpP2PCallBack is a function callback from http deamon implemented with p2p protocol,
pub trait HttpdImpP2PCallBack: Sync + Send {
    /// on_httpd_p2p_ready: callback when httpd is open ready.
    fn on_httpd_p2p_ready(
        &self,
        web_root_host: String, // web root local host address.
    ) -> i64;
}

/// HttpdImpP2PContract: is a http deamon which implement p2p protocol.
pub trait HttpdImpP2PContract {
    /// loop_block_on_httpd: start a http deamon, loop block means infinity run or unwrap inner then break.
    fn loop_block_on_httpd(
        // httpd router handle local file url path, default is "/static"
        root_path: String,
        // httpd router local root dir path.
        root_dir_path: String,
        // httpd handle remote file url path, default is "/remote"
        remote_path: String,
        // httpd handle remote file url path, default is "/remote"
        remote_file_map: String,
        // httpd listen host, default is 0.0.0.0,means local ip address.
        http_host: String,
        // httpd listen port，defautl is 0,measns listen on random port，
        // when started ready, will callback listen address host:port by on_httpd_p2p_ready
        http_port: u16,
        // set httpd start|stop ... event callback point.
        callback: Box<dyn HttpdImpP2PCallBack>,
    ) -> SDKApiResult;
    /// stop_httd: stop the http deamon.
    fn stop_httd() -> SDKApiResult;
    /// get_httpd_host: get http deamon root host.
    fn get_httpd_host() -> SDKApiResult;
    /// get_httpd_host_merge_lan: get http deamon root host,perfer lan host.
    fn get_httpd_host_prefer_lan(
        remote_client_id: String,
        root_path: String,
        file_id: String,
    ) -> SDKApiResult;
}
